/* Texture functions for cs580 GzLib	*/
#include "stdafx.h" 
#include "stdio.h"
#include "Gz.h"
#include "math.h"

#define N 500

/*The structure of complex number using in procedural texture*/
#ifndef COMPLEX
#define COMPLEX
typedef struct {
	float real;
	float image;
} Complex;
#endif

void ComplexMultiply(Complex *x,Complex *y,Complex *result);
void ComplexAdd(Complex *x,Complex *y,Complex *result);
float ComplexLength(Complex *x);
void ColorLUT(float scalar,GzColor color);

GzColor	*image;
int xs,ys;
int reset = 1;

/* Image texture function */
int tex_fun(float u, float v, GzColor color)
{
	unsigned char pixel[3];
	unsigned char dummy;
	char foo[8];
	int i, j;
	FILE *fd;
	float s,t;
	int A,B,C,D;

	if (reset) {          /* open and load texture file */
		fd = fopen ("texture", "rb");
		if (fd == NULL) {
			fprintf (stderr, "texture file not found\n");
			exit(-1);
		}
		fscanf (fd, "%s %d %d %c", foo, &xs, &ys, &dummy);
		image = (GzColor*)malloc(sizeof(GzColor)*(xs+1)*(ys+1));
		if (image == NULL) {
			fprintf (stderr, "malloc for texture image failed\n");
			exit(-1);
		}

		for (i = 0; i < xs*ys; i++) {	/* create array of GzColor values */
			fread(pixel, sizeof(pixel), 1, fd);
			image[i][RED] = (float)((int)pixel[RED]) * (1.0 / 255.0);
			image[i][GREEN] = (float)((int)pixel[GREEN]) * (1.0 / 255.0);
			image[i][BLUE] = (float)((int)pixel[BLUE]) * (1.0 / 255.0);
		}

		reset = 0;          /* init is done */
		fclose(fd);
	}

/* bounds-test u,v to make sure nothing will overflow image array bounds */
/* determine texture cell corner values and perform bilinear interpolation */
/* set color to interpolated GzColor value and return */

	/*Scale u,v to texture image size*/
	/*Bound-check to make sure nothing will overflow*/
	u=u*(xs-1);
	v=v*(ys-1);
	if(u<0)
	{
		u=0;
	}
	else if(u>(xs-1))
	{
		u=(float)xs-1;
	}
	if(v<0)
	{
		v=0;
	}
	else if(v>(ys-1))
	{
		v=(float)ys-1;
	}
	/************************************************/

	/*Determine texture cell corner values*/
	s=u-floor(u);
	t=v-floor(v);
	A=(u-s)+(v-t)*xs;
	B=(u+1-s)+(v-t)*xs;
	C=(u+1-s)+(v+1-t)*xs;
	D=(u-s)+(v+1-t)*xs;
	/**************************************/
	/*Perform Bilinear Interpolation*/
	color[RED]=s*t*image[C][RED]+(1-s)*t*image[D][RED]+s*(1-t)*image[B][RED]+(1-s)*(1-t)*image[A][RED];
	color[GREEN]=s*t*image[C][GREEN]+(1-s)*t*image[D][GREEN]+s*(1-t)*image[B][GREEN]+(1-s)*(1-t)*image[A][GREEN];
	color[BLUE]=s*t*image[C][BLUE]+(1-s)*t*image[D][BLUE]+s*(1-t)*image[B][BLUE]+(1-s)*(1-t)*image[A][BLUE];
	/********************************/

	return GZ_SUCCESS;
}

/* Procedural texture function */
int ptex_fun(float u, float v, GzColor color)
{
	int i;
	int flag=0;;
	float length;

	/*X=X*X+C*/
	Complex *x=(Complex*)operator new (sizeof(Complex));
	x->real=3*(u-0.5);
	x->image=2*(v-0.5);

	Complex *c=(Complex*)operator new (sizeof(Complex));
	c->real=-0.012;
	c->image=0.74;

	Complex *result=(Complex*)operator new (sizeof(Complex));
	result->real=0.0;
	result->image=0.0;

	/*Iteratively calculate X until iteration ends or the length of X is larger than 2, which means it is infinite*/
	for(i=0;(i<N)&&((x->real*x->real+x->image*x->image)<4);i++)
	{
		result->real=x->real*x->real-x->image*x->image+c->real;
		result->image=2*x->real*x->image+c->image;
		x->real=result->real;
		x->image=result->image;
		flag=i;
	}
	/*Look up to color table to get texture color*/
	ColorLUT((flag==N?0.0:((float)flag)/250),color);

	return GZ_SUCCESS;
}

void ComplexMultiply(Complex *x,Complex *y,Complex *result)
{//The multiply of two complex numbers
	result->real=x->real*y->real-x->image*y->image;
	result->image=x->real*y->image+x->image*y->real;
}

void ComplexAdd(Complex *x,Complex *y,Complex *result)
{//The addition of two complex numbers
	result->real=x->real+y->real;
	result->image=x->image+y->image;
}

float ComplexLength(Complex *x)
{//The length of a complex number
	float result;
	result=sqrt(abs(x->real*x->real)+abs(x->image*x->image));
	return result;
}

void ColorLUT(float scalar,GzColor color)
{//Initialize the look up table, and then use bilinear interpolation to get texture color
	float a,b;

	GzColor LUT[11];
	LUT[0][RED]=0;
	LUT[0][GREEN]=0;
	LUT[0][BLUE]=0;
	LUT[1][RED]=1;
	LUT[1][GREEN]=0;
	LUT[1][BLUE]=0;
	LUT[2][RED]=1;
	LUT[2][GREEN]=1;
	LUT[2][BLUE]=0;
	LUT[3][RED]=1;
	LUT[3][GREEN]=1;
	LUT[3][BLUE]=0.5;
	LUT[4][RED]=1;
	LUT[4][GREEN]=1;
	LUT[4][BLUE]=0.75;
	LUT[5][RED]=1;
	LUT[5][GREEN]=1;
	LUT[5][BLUE]=1;
	LUT[6][RED]=1;
	LUT[6][GREEN]=1;
	LUT[6][BLUE]=0.75;
	LUT[7][RED]=1;
	LUT[7][GREEN]=1;
	LUT[7][BLUE]=0.5;
	LUT[8][RED]=1;
	LUT[8][GREEN]=1;
	LUT[8][BLUE]=0;
	LUT[9][RED]=1;
	LUT[9][GREEN]=0;
	LUT[9][BLUE]=0;
	LUT[10][RED]=0;
	LUT[10][GREEN]=0;
	LUT[10][BLUE]=0;

	if((scalar>0)&&(scalar<0.2))
	{
		a=(scalar-0)/0.2;
		b=(0.2-scalar)/0.2;
		color[RED]=LUT[0][RED]*a+LUT[1][RED]*b;
		color[GREEN]=LUT[0][GREEN]*a+LUT[1][GREEN]*b;
		color[BLUE]=LUT[0][BLUE]*a+LUT[1][BLUE]*b;
	}
	else if((scalar>0.2)&&(scalar<0.4))
	{
		a=(scalar-0.2)/0.2;
		b=(0.4-scalar)/0.2;
		color[RED]=LUT[1][RED]*a+LUT[2][RED]*b;
		color[GREEN]=LUT[1][GREEN]*a+LUT[2][GREEN]*b;
		color[BLUE]=LUT[1][BLUE]*a+LUT[2][BLUE]*b;
	}
	else if((scalar>0.4)&&(scalar<0.6))
	{
		a=(scalar-0.4)/0.2;
		b=(0.6-scalar)/0.2;
		color[RED]=LUT[2][RED]*a+LUT[3][RED]*b;
		color[GREEN]=LUT[2][GREEN]*a+LUT[3][GREEN]*b;
		color[BLUE]=LUT[2][BLUE]*a+LUT[3][BLUE]*b;
	}
	else if((scalar>0.6)&&(scalar<0.8))
	{
		a=(scalar-0.6)/0.2;
		b=(0.8-scalar)/0.2;
		color[RED]=LUT[3][RED]*a+LUT[4][RED]*b;
		color[GREEN]=LUT[3][GREEN]*a+LUT[4][GREEN]*b;
		color[BLUE]=LUT[3][BLUE]*a+LUT[4][BLUE]*b;
	}
	else if((scalar>0.8)&&(scalar<1.0))
	{
		a=(scalar-0.8)/0.2;
		b=(1.0-scalar)/0.2;
		color[RED]=LUT[4][RED]*a+LUT[5][RED]*b;
		color[GREEN]=LUT[4][GREEN]*a+LUT[5][GREEN]*b;
		color[BLUE]=LUT[4][BLUE]*a+LUT[5][BLUE]*b;
	}
	else if((scalar>1.0)&&(scalar<1.2))
	{
		a=(scalar-1.0)/0.2;
		b=(1.2-scalar)/0.2;
		color[RED]=LUT[5][RED]*a+LUT[6][RED]*b;
		color[GREEN]=LUT[5][GREEN]*a+LUT[6][GREEN]*b;
		color[BLUE]=LUT[5][BLUE]*a+LUT[6][BLUE]*b;
	}
	else if((scalar>1.20)&&(scalar<1.4))
	{
		a=(scalar-1.2)/0.2;
		b=(1.4-scalar)/0.2;
		color[RED]=LUT[6][RED]*a+LUT[7][RED]*b;
		color[GREEN]=LUT[6][GREEN]*a+LUT[7][GREEN]*b;
		color[BLUE]=LUT[6][BLUE]*a+LUT[7][BLUE]*b;
	}
	else if((scalar>1.4)&&(scalar<1.6))
	{
		a=(scalar-1.4)/0.2;
		b=(1.6-scalar)/0.2;
		color[RED]=LUT[7][RED]*a+LUT[8][RED]*b;
		color[GREEN]=LUT[7][GREEN]*a+LUT[8][GREEN]*b;
		color[BLUE]=LUT[7][BLUE]*a+LUT[8][BLUE]*b;
	}
	else if((scalar>1.6)&&(scalar<1.8))
	{
		a=(scalar-1.6)/0.2;
		b=(1.8-scalar)/0.2;
		color[RED]=LUT[8][RED]*a+LUT[9][RED]*b;
		color[GREEN]=LUT[8][GREEN]*a+LUT[9][GREEN]*b;
		color[BLUE]=LUT[8][BLUE]*a+LUT[9][BLUE]*b;
	}
	else if((scalar>1.8)&&(scalar<2.0))
	{
		a=(scalar-1.8)/0.2;
		b=(2.0-scalar)/0.2;
		color[RED]=LUT[9][RED]*a+LUT[10][RED]*b;
		color[GREEN]=LUT[9][GREEN]*a+LUT[10][GREEN]*b;
		color[BLUE]=LUT[9][BLUE]*a+LUT[10][BLUE]*b;
	}
	else if(scalar==0)
	{
		color[RED]=LUT[0][RED];
		color[GREEN]=LUT[0][GREEN];
		color[BLUE]=LUT[0][BLUE];
	}
	else if(scalar==0.2)
	{
		color[RED]=LUT[1][RED];
		color[GREEN]=LUT[1][GREEN];
		color[BLUE]=LUT[1][BLUE];
	}
	else if(scalar==0.4)
	{
		color[RED]=LUT[2][RED];
		color[GREEN]=LUT[2][GREEN];
		color[BLUE]=LUT[2][BLUE];
	}
	else if(scalar==0.6)
	{
		color[RED]=LUT[3][RED];
		color[GREEN]=LUT[3][GREEN];
		color[BLUE]=LUT[3][BLUE];
	}
	else if(scalar==0.8)
	{
		color[RED]=LUT[4][RED];
		color[GREEN]=LUT[4][GREEN];
		color[BLUE]=LUT[4][BLUE];
	}
	else if(scalar==1.0)
	{
		color[RED]=LUT[5][RED];
		color[GREEN]=LUT[5][GREEN];
		color[BLUE]=LUT[5][BLUE];
	}
	else if(scalar==1.2)
	{
		color[RED]=LUT[6][RED];
		color[GREEN]=LUT[6][GREEN];
		color[BLUE]=LUT[6][BLUE];
	}
	else if(scalar==1.4)
	{
		color[RED]=LUT[7][RED];
		color[GREEN]=LUT[7][GREEN];
		color[BLUE]=LUT[7][BLUE];
	}
	else if(scalar==1.6)
	{
		color[RED]=LUT[8][RED];
		color[GREEN]=LUT[8][GREEN];
		color[BLUE]=LUT[8][BLUE];
	}
	else if(scalar==1.8)
	{
		color[RED]=LUT[9][RED];
		color[GREEN]=LUT[9][GREEN];
		color[BLUE]=LUT[9][BLUE];
	}
	else if(scalar==2.0)
	{
		color[RED]=LUT[10][RED];
		color[GREEN]=LUT[10][GREEN];
		color[BLUE]=LUT[10][BLUE];
	}
}